//
//  StringExtension.swift
//  PassVPN
//
//  Created by yiwanjun on 2018/1/8.
//  Copyright © 2018年 Asteroid. All rights reserved.
//

import UIKit
public extension NSString{
    
    /// 高亮某些字符串
    /// - Parameters:
    ///   - subString: 需要高亮的字符串
    ///   - color: 高亮颜色
    ///   - fontsize: 高亮字体大小，默认使用系统字体
    /// - Returns: NSMutableAttributedString
    @objc func fontSizeAndColorSubString(_ subString: String, color: UIColor, fontsize: CGFloat) -> NSMutableAttributedString {
        return highlightSubstring(subString, color: color, font: UIFont.systemFont(ofSize: fontsize))
    }
    /// 高亮某些字符串
    /// - Parameters:
    ///   - subString: 需要高亮的字符串
    ///   - color: 高亮颜色
    ///   - font: 高亮字体
    /// - Returns: NSMutableAttributedString
    @objc func highlightSubstring(_ subString: String, color: UIColor, font: UIFont) -> NSMutableAttributedString {
        var start = 0
        var ranges: [NSRange] = []
        while true {
            let range = (self as NSString).range(of: subString, options: NSString.CompareOptions.literal, range: NSRange(location: start, length: (self as NSString).length - start))
            if range.location == NSNotFound {
                break
            } else {
                ranges.append(range)
                start = range.location + range.length
            }
        }
        let attrText = NSMutableAttributedString(string: self as String)
        for range in ranges {
            
            attrText.addAttribute(NSAttributedString.Key.font, value: font, range: range)
            attrText.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
        }
        return attrText
    }
}
public extension String {
    
    /// 拼接富文本
    /// - Parameters:
    ///   - subString: 富文本内容
    ///   - color: 富文本颜色
    ///   - fontsize: 富文本字体大小，默认时候用系统字体
    /// - Returns: NSMutableAttributedString
    mutating func appendRichString(_ subString: String, color: UIColor, fontsize: CGFloat) -> NSMutableAttributedString{
        self += subString
        return self.fontSizeAndColorSubString(subString, color: color, fontsize: fontsize)
    }
    
    /// 拼接富文本
    /// - Parameters:
    ///   - subString: 富文本内容
    ///   - color: 富文本颜色
    ///   - font: 富文本字体
    /// - Returns: NSMutableAttributedString
    mutating func appendRichString(_ subString: String, color: UIColor, font: UIFont) -> NSMutableAttributedString{
        self += subString
        var attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key: Any]()
        attributes[NSAttributedString.Key.font] = font
        attributes[NSAttributedString.Key.foregroundColor] = color
        return fontSizeAndColorSubString(subString, attributes: attributes)
    }
    
    /// 高亮某些字符串
    /// - Parameters:
    ///   - subString: 需要高亮的字符串
    ///   - color: 高亮颜色
    ///   - font: 高亮字体
    /// - Returns: NSMutableAttributedString
    func highlightSubstring(_ subString: String, color: UIColor, font: UIFont) -> NSMutableAttributedString {
        var attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key: Any]()
        attributes[NSAttributedString.Key.font] = font
        attributes[NSAttributedString.Key.foregroundColor] = color
        return fontSizeAndColorSubString(subString, attributes: attributes)
    }
    
    /// 自定添加下划线的富文本
    /// - Parameters:
    ///   - color: 颜色
    ///   - font: 紫铜
    /// - Returns: NSMutableAttributedString
    func addUnderline(color: UIColor, font: UIFont) -> NSMutableAttributedString{
        var subAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key: Any]()
        subAttributes[NSAttributedString.Key.font] = font
        subAttributes[NSAttributedString.Key.foregroundColor] = color
        subAttributes[NSAttributedString.Key.underlineStyle] = NSUnderlineStyle.single.rawValue
        
        return fontSizeAndColorSubString(self, attributes: subAttributes)
    }
    
    /// 通过传入的属性字典高亮文本
    /// - Parameters:
    ///   - subString: 需要高亮的文本
    ///   - attributes: 属性字典
    /// - Returns: NSMutableAttributedString
    func fontSizeAndColorSubString(_ subString: String, attributes: [NSAttributedString.Key : Any]) -> NSMutableAttributedString {
        return highlightSubStringWithDictionary([subString: attributes])
    }
    
    /// 通过传入的属性字典高亮文本
    /// - Parameter subStringDic: [String: [NSAttributedString.Key : Any]]，文本和对应属性
    /// - Returns: NSMutableAttributedString
    func highlightSubStringWithDictionary(_ subStringDic: [String: [NSAttributedString.Key : Any]]) -> NSMutableAttributedString {
        let attrText = NSMutableAttributedString(string: self)
        
        for subString in subStringDic.keys {
            let ranges: [NSRange] = stringRange(subString)
            for range in ranges {
                attrText.addAttributes((subStringDic[subString]!) as [NSAttributedString.Key : Any], range: range)
            }
        }
        return attrText
    }
    
    /// 获取子串的NSRange
    /// - Parameter subString: 子串
    /// - Returns: NSRange
    func stringRange(_ subString: String) -> [NSRange]{
        var start = 0
        var ranges: [NSRange] = []
        while true {
            let range = (self as NSString).range(of: subString, options: NSString.CompareOptions.literal, range: NSRange(location: start, length: (self as NSString).length - start))
            if range.location == NSNotFound {
                break
            } else {
                ranges.append(range)
                start = range.location + range.length
            }
        }
        return ranges
    }
}

public extension String {
    func localPrice() -> Self {
        "¥\(self)"
    }
    
    func dotPrice() -> String {
        
        var res : [Character] = []
        let reverse = reversed()
        var index: Int = 0
        for char in reverse {
            if index != 0 , index%3 == 0 {
                res.append(".")
            }
            res.append(char)
            index += 1
        }
        let content = String(res)
        return String(content.reversed())
    }
    //千分位按逗号分隔
    var dotSeparate: String {
        var res = ""
        let reversedArr = Array(self.reversed())
        for i in 0..<reversedArr.count {
            if i != 0 , i % 3 == 0 {
                res.append(",")
            }
            res.append(reversedArr[i])
        }
        return String(res.reversed())
    }
    
}

public extension String {
    
    func stringWidthWithSpace(font: UIFont, height: CGFloat = 15) -> CGFloat{
        return stringWidth(font: font, height: height) + 20
    }
    func stringSize(font: UIFont, maxWidth: CGFloat) -> CGSize {
        let rect: CGRect = NSString(string: self).boundingRect(with: CGSize(width: maxWidth, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        return rect.size
    }
    func stringWidth(font: UIFont, height: CGFloat = 15) -> CGFloat {
        let rect = NSString(string: self).boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        return ceil(rect.width)
    }
    
    func stringHight(font: UIFont, width: CGFloat) -> CGFloat {
        let rect = NSString(string: self).boundingRect(with: CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        return ceil(rect.height)
    }
    
    func ch_heightForComment(font: UIFont, width: CGFloat, maxHeight: CGFloat) -> CGFloat {
        
        let rect = NSString(string: self).boundingRect(with: CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        return ceil(rect.height)>maxHeight ? maxHeight : ceil(rect.height)
    }
    
    func ch_timeStampToString(timeStamp:String)->String {
        
        let string = NSString(string: timeStamp)
        let timeSta:TimeInterval = string.doubleValue
        let dfmatter = DateFormatter()
        dfmatter.dateFormat="MM月dd日HH:mm"
        let date = NSDate(timeIntervalSince1970: timeSta)
        return dfmatter.string(from: date as Date)
    }
    
    //最近几分钟展示
    func recentlyTime(formatter: String = "yyyy-MM-dd HH:mm") -> String?{
        guard let timeInterval = timeDate(formatter: formatter)?.timeIntervalSince1970 else{
            return nil
        }
        let createDate = Int(timeInterval)
        
        var result = ""
        
        //当前时间的时间戳
        let nowTimeInterval: TimeInterval = Date().timeIntervalSince1970
        let timeStamp = Int(nowTimeInterval * 1000)
        
        let timeNumber = (timeStamp - createDate) / 1000
        if timeNumber <= 5 {
            result = "刚刚"
        }
        else if  timeNumber <= 59{
            result = "\(timeNumber)秒前"
        }else if timeNumber >= 60 && timeNumber < 3600{
            
             result = "\(timeNumber/60)分钟前"
        }else if timeNumber >= 3600 && timeNumber < 86400{
            
             result = "\(timeNumber/3600)小时前"
        }else{
            result = self
        }
        return result
    }
    
    
    func timeDate(formatter:String = "yyyy-MM-dd HH:mm:ss") -> Date? {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = formatter
        let date = dateFormatter.date(from: self)
        return date
    }
    
    ///毫秒级时间戳
    func timestamp(formatter:String = "yyyy-MM-dd HH:mm:ss") -> String? {
        let date = timeDate(formatter: formatter)
        
        if let timeInterval =  date?.timeIntervalSince1970 {
            let millisecond = timeInterval * 1000
            return Int(millisecond).string
        }
        return nil
    }
    
    ///本地化时间
    func timeLocalized(formatter:String = "yyyy-MM-dd HH:mm:ss") -> String {
        
        if let date = timeDate(formatter: formatter) {
            var style = DateFormatter.Style.short
            if formatter == "yyyy-MM-dd" {
                style = .none
            }
            return DateFormatter.localizedString(from: date, dateStyle: .medium, timeStyle: style)
        }
        return ""
    }
    
    func emptyToNil() -> String?{
        if self == ""{
            return nil
        }
        return self
    }
    
    func isNull() -> Bool {
        self == "null" || self == "NULL"
    }
    
    
    func isNotEmpaty() -> Bool {
        !isEmpty
    }
    
    func playerTime(formatter:String = "mm:ss") -> String {
        guard let timeFlag = self.toDouble() else {
            return ""
        }
        let date = Date(timeIntervalSince1970: timeFlag)
        let dataFormatter = DateFormatter()
        dataFormatter.dateFormat = formatter
        return dataFormatter.string(from: date)
    }
    
    func parseQueryStringToDictionary() -> [String: String] {
        var params = [String: String]()
        
        // 将字符串按照"?"分割，获取参数部分
        let parts = split(separator: "?", maxSplits: 1).map { $0.trimmingCharacters(in: .whitespaces) }
        if parts.count > 1 {
            let pairs = parts[1].split(separator: "&")
            
            for pair in pairs {
                let keyValue = pair.split(separator: "=", maxSplits: 1).map { $0.trimmingCharacters(in: .whitespaces) }
                if keyValue.count == 2 {
                    let key = keyValue[0]
                    let value = keyValue[1]
                    params[key] = value
                }
            }
        }
        
        return params
    }
}

public extension String {
    ///range转换为NSRange
    func nsRange(from range: Range<String.Index>) -> NSRange {
        return NSRange(range, in: self)
    }
    
    func match(string: String) -> [NSRange] {
        var allLocation = [Int]() //所有起点
        let matchStrLength = (string as NSString).length  //currStr.characters.count 不能正确统计表情
        let arrayStr = self.components(separatedBy: string)
        var currLoc = 0
        arrayStr.forEach { currStr in
            currLoc += (currStr as NSString).length
            allLocation.append(currLoc)
            currLoc += matchStrLength
        }
        allLocation.removeLast()
        return allLocation.map { NSRange(location: $0, length: matchStrLength) } //可把这段放在循环体里面，同步处理，减少再次遍历的耗时
    }
}

public extension String{
    func unicodeToString() -> String?{
        //Unicode to String
        let datadec  = self.data(using: String.Encoding.utf8)
        let decodevalue = String(data: datadec!, encoding: String.Encoding.nonLossyASCII)
        return decodevalue
    }
    
    func stringToUnicode() -> String?{
        //String to Unicode
        let datadec = self.data(using: .nonLossyASCII)
        let datadeValue = String(data: datadec!, encoding: .utf8)
        return datadeValue
    }
    
    ///去掉字符串中所有的空格
    func trimSpace() -> String{
        return self.replacingOccurrences(of: " ", with: "")
    }
    
    ///去掉字符串前后的空格和回车
    func trim() -> String {
        return self.trimmingCharacters(in: .whitespacesAndNewlines)
    }
    
    func toDictionary() -> [String: Any]?{
        if self.utf8CString.count <= 1{
            return nil
        }
        guard let data: Data = self.data(using: .utf8) else {
            return nil
        }
        do {
            let dicAny = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions())
            guard let dic : Dictionary = dicAny as? [String: Any] else{
                return nil
            }
            return dic
            
        } catch  {
            return nil
        }
    }
    
    func toUnichar() -> unichar{
        return (self as NSString).character(at: 0)
    }
    
    func toDouble() -> Double? {
        Double(self)
    }
}

public extension String{
    func jsonDictionary() -> [String : Any]?{
        var dic: [String : Any]? = nil
        do {
            dic = try JSONSerialization.jsonObject(with: self.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions.allowFragments) as? [String : Any]
        } catch  {
            return nil
        }
        return dic
    }
    
    func jsonArray() -> [Any]?{
        var arr: [Any]? = nil
        do {
            arr = try JSONSerialization.jsonObject(with: self.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions.allowFragments) as? [Any]
        } catch  {
            return nil
        }
        return arr
    }
}

public extension NSMutableAttributedString {
    func  appendRichString(_ subString: String, color: UIColor, font: UIFont, lineSpacing: CGFloat? = nil) {
        
        var attributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: color]
        
        if let lineSpacing = lineSpacing {
            let style = NSMutableParagraphStyle()
            style.lineSpacing = lineSpacing
            attributes[NSAttributedString.Key.paragraphStyle] = style
        }
        
        let append = NSMutableAttributedString(string: subString, attributes: attributes)
        self.append(append)
    }
}

public extension String {
    
    func appVersion() -> Double{
        var version: Double = 0.0
        let results: [Substring] = self.split(separator: ".")
        
        func poewr(p: Int) -> Double{
            return pow(100, Double(p))
        }
        
        var index: Int = 0
        for item in results.reversed() {
            if let sub: Double = Double(item) {
                let pow: Double = poewr(p: index)
                version += pow * sub
            }
            index += 1
        }
        return version
    }
}

public extension String {
    static func getRandomStringOfLength(length: Int) -> String {
        let characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        var ranStr = ""
        for _ in 0..<length {
            if let ch = characters.randomElement() {
                ranStr.append(ch)
            }
        }
        return ranStr
    }
}

public extension String {
    func formatToPhone() -> String {
        var phone = ""
        for (index, chat) in self.enumerated() {
            if index == 3 || index == 7 {
                phone.append("-")
            }
            phone.append(chat)
        }
        return phone
    }
}
